package hight;

import java.util.concurrent.locks.StampedLock;

/**
 * 乐观读readLock
 * tryOptimisitcRead通过名字来记忆很简单，try代表尝试，说明他是无阻塞的，Optimistic乐观的
 * Read代表读锁
 * 乐观锁认为数据不会轻易的被修改，因此在操作前并没有加锁，（使用cas方式更新锁的状态）
 * 而是采用试探的方式，只要当前没有写锁就可以获取一个非0的stamp,如果已经存在写锁则返回一个为0的stamp
 * 没有使用cas方法，也没有正真的加锁，所以并发性能要比readLock还要高
 * 由于没有使用真锁，若中途被修改，就会造成数据不一致的问题
 * 但是stampLock使用快照的方式，需要复制一份要操作的变量到方法栈，操作的数据只是一个快照，从而保证了数据的
 * 最终一致性，但是读线程可能使用的数据不是最新的，特别适合读多写少的高并发场景
 */
public class StampedLockTest2 {
    // 与 ReentrantReadWirteLock 功能类似提供三种读写锁
    // StampedLock中映入了一个stamp(邮戳)的概念，他代表线程获取到锁的版本，每一把锁都有唯一的stamp
    // 写锁wirteLock 时排他锁，也叫独占锁，相同时间只能有一个线程获取锁，其他线程请求读锁和写锁都会被阻塞
    // 功能类似与ReentrantReadWriteLick.wirteLock
    // 区别时StampedLock的写锁时不可重入锁，当前没有线程持有读锁和写锁的时候才可以获得获取到该锁
    // 读读共享，写写互斥，读写互斥

    // tryOptimisticRead与validate一定要紧紧挨着使用，否则在获取和验证之间很可能数据被修改，如果这期间锁发生变化
    // 则calidate返回false,否则返回true
    public static void main(String[] args) {
        StampedLock s1 = new StampedLock();
        //乐观锁
        long stamp = s1.tryOptimisticRead();
        System.out.println(Thread.currentThread().getName() + " 尝试获取乐观锁" + stamp);
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"run");
            long stmp1 = s1.writeLock();
            //long stmp1 = s1.readLock();
            System.out.println(Thread.currentThread().getName() + "get write lock1,stamp = " + stmp1);
             s1.unlockWrite(stmp1);
            //s1.unlockRead(stmp1);
            System.out.println(Thread.currentThread().getName() + "unlock write look1,stamp=" + s1);
        }).start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 验证是否发生过变化
        boolean validate = s1.validate(stamp);
        System.out.println(Thread.currentThread().getName() + "tryOptimisticRead validtae=" + validate);
        stamp = s1.tryOptimisticRead();
        validate = s1.validate(stamp);
        System.out.println(Thread.currentThread().getName() + "tryOptimisticRead validtae=" + validate);

    }
}
